/*globals escape, Ozone, widgetEventingController:true, JSON:true */


function CoreHash() {
    var i;

    this.length = 0;
    this.items = [];
    for (i = 0; i < arguments.length; i += 2) {
        if (typeof (arguments[i + 1]) !== 'undefined') {
            this.items[arguments[i]] = arguments[i + 1];
            this.length += 1;
        }
    }

    this.removeItem = function (in_key) {
        var tmp_previous = null;
        if (typeof (this.items[in_key]) !== 'undefined') {
            this.length -= 1;
            tmp_previous = this.items[in_key];
            delete this.items[in_key];
        }

        return tmp_previous;
    };

    this.getItem = function (in_key) {
        return this.items[in_key];
    };

    this.setItem = function (in_key, in_value) {
        var tmp_previous = null;
        if (typeof (in_value) !== 'undefined') {
            if (typeof (this.items[in_key]) === 'undefined') {
                this.length += 1;
            } else {
                tmp_previous = this.items[in_key];
            }

            this.items[in_key] = in_value;
        }

        return tmp_previous;
    };

    this.hasItem = function (in_key) {
        return typeof (this.items[in_key]) !== 'undefined';
    };

    this.clear = function () {
        var i = 0;

        for (i in this.items) {
            if (this.items.hasOwnProperty(i)) {
                delete this.items[i];
            }
        }

        this.length = 0;
    };
}

/**
 * Modifiers defines a set of properties to give appropriate symbol modifiers to MIL-STD-2525 Symbols.
 * @class Modifiers
 */

function Modifiers() {
    /**
     *  A graphic modifier in a boundary graphic that identifies command level (see 5.5.2.2, table V, and
     *  figures 10 and 12).  Uses a string as input. Corresponds to label "C" in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *       Warfighting Symbols: Equipment
     *       Tactical Graphics: Nuclear
     *  Length: 6
     *  @var {string} ? public
     */
    this.quantity;

    /**
     *  A text modifier that displays "(+)" for reinforced, "(-)" for
     *  reduced, and "(+/-)" for reinforced and reduced. Takes in a string.
     *  Corresponds to label "F" in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Units, Stability Operations
     *  Tactical Graphics: Not used
     *  Length: 3
     *  @var {string} ? public
     */
    this.reinforcedOrReduced;

    /**
     *  A text modifier for units, equipment and installations; content
     *  is implementation specific.  Takes in a string.
     *  Corresponds to label "G" in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Units, Equipment, Installation, Signal Intelligence, Stability Operations
     *  Tactical Graphics: Not used
     *  Length: 20
     *  @var {string} ? public
     */
    this.staffComments;

    /**
     *  A text modifier for tactical graphics; content is
     *  implementation specific. Takes in a string.
     *  Corresponds to label "H"
     *  in the MIL-STD-2525C
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Units, Equipment, Installation, Signal Intelligence, Stability Operations,
     *  EMS Units, EMS equipment and incidents, EMS installations
     *  Tactical Graphics: Points, Lines, Areas, Nuclear, Bio/Chem
     *  Length: 20
     *  @var {string} ? public
     */
    this.additionalInfo1;

    /**
     *  A text modifier for tactical graphics; content is
     *  implementation specific. Takes in a string.
     *  Corresponds to label "H1"
     *  in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Not used
     *  Tactical Graphics: Points, Lines, Areas, Nuclear, Bio/Chem
     *  Length: 20
     *  @var {string} ? public
     */
    this.additionalInfo2;

    /**
     *  A text modifier for tactical graphics; content is
     *  implementation specific. Takes in a string.
     *  Corresponds to label "H2"
     *  in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Not used
     *  Tactical Graphics: Points, Lines, Areas, Nuclear, Bio/Chem
     *  Length: 20
     *  @var {string} ? public
     */
    this.additionalInfo3;

    /**
     *  A text modifier for units, equipment, and installations that consists of a one-letter
     *  reliability rating and a one-number credibility rating:
     *  Reliability Ratings: A-completely reliable, B-usually reliable, C-fairly reliable,
     *  D-not usually reliable, E-unreliable, F-reliability cannot be judged.
     *  Credibility Ratings: 1-confirmed by other sources,
     *  2-probably true, 3-possibly true, 4-doubtfully true,
     *  5-improbable, 6-truth cannot be judged. Takes in a string.
     *  Corresponds to label "J" in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Units, Equipment, Installation, Signal Intelligence, Stability Operations,
     *  EMS Units, EMS equipment and incidents, EMS installations
     *  Tactical Graphics: Not used
     *  Length: 2
     *  @var {string} ? public
     */
    this.evaluationRating;

    /**
     *  A text modifier for units and installations that indicates unit effectiveness or
     *  installation capability. Takes in a string.
     *  Corresponds to label "K" in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Units, Installation, Stability Operations
     *  Tactical Graphics: Not used
     *  Length: 5/3
     *  @var {string} ? public
     */
    this.combatEffectiveness;

    /**
     *  A text modifier for hostile equipment; "!" indicates detectable electronic signatures.
     *  Takes in a string.
     *  Corresponds to label "L" in the MIL-STD-2525C.
     *  Valid for the following categories of graphics:
     *  Warfighting Symbols: Equipment, Signal Intelligence
     *  Tactical Graphics: Not used
     *  Length: 1
     *  @var {string} ? public
     */
    this.signatureEquipment;

    /**
    A text modifier for units that indicates the number or title of higher 
    echelon command (Corps are designated by Roman numerals).
    Takes in a string.
    Corresonds to label "M" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Signal Intelligence
    Tactical Graphics: Not used
    Length: 21
    @var {string} ? public
    */
    this.higherFormation;

    /**
    A text modifier for tactical graphics; letters "ENY" denote hostile symbols.
    Takes in a string.
    Corresponds to label "N" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Equipment
    Tactical Graphics: Points, Lines, Areas, Boundary Lines, Nuclear, Bio/Chem
    Length: 3
    @var {string} ? public
    */
    this.hostile;

    /**
    A text modifier displaying IFF/SIF identification modes and codes.
    Takes in a string.
    Corresponds to label "P" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Installation, Stability Operations
    Tactical Graphics: Not used
    Length: 5
    @var {string} ? public
    */
    this.iffSif;

    /**
    A graphic modifier for units and CBRN events that
    identifies the direction of movement (see 5.5.2.1
    and figure 11).  Takes in a string representing 
    the numbers "0"-"359".
    Corresponds to label "Q" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Stability Operations, 
    EMS Units, EMS equipment and incidents
    Tactical Graphics: Nuclear, Bio/Chem
    Length: G
    @var {string} ? public
    */
    this.directionOfMovement;

    /**
    A graphic modifier for points and CBRN events
    used when placing an object away from its actual
    location (see 5.5.2.3 and figures 10, 11, and 12).
    Takes in a string.
    Corresponds to label "S" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Not used
    Tactical Graphics: Points, Nuclear, Bio/Chem
    Length: G
    @var {string} ? public
    */
    this.offsetIndicator;

    /**
    A text modifier that uniquely identifies a particular
    tactical graphic, symbol, or track number.
    Nuclear: delivery unit (missile, aircraft, satellite,
    etc.) Takes in a string.
    Corresponds to label "T" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Installation, Signal Intelligence, Stability Operations, 
    EMS Units, EMS equipment and incidents, EMS installations
    Tactical Graphics:Points, Lines, Areas, Boundary Lines, Nuclear, Bio/Chem
    Length: 15 (35 for Boundary Lines)
    @var {string} ? public
    */
    this.uniqueDesignation1;

    /**
    A text modifier that uniquely identifies a particular
    tactical graphic; track number.
    Nuclear: delivery unit (missile, aircraft, satellite,
    etc.) Takes in a string.
    Corresponds to label "T1" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Not used
    Tactical Graphics: Points, Lines, Areas, Boundary Lines, Nuclear, Bio/Chem
    Length: 15 (35 for Boundary Lines)
    @var {string} ? public
    */
    this.uniqueDesignation2;

    /**
    A text modifier that indicates type of equipment or nuclear weapon type.
    Takes in a string.
    Corresponds to label "V" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Equipment, Signal Intelligence, EMS equipment and incidents
    Tactical Graphics: Not used
    Length: 20
    @var {string} ? public
    */
    this.equipmentType;

    /**
    A text modifier for units, equipment, and installations that displays DTG format:
    DDHHMMSSZMONYYYY or O/O for an order(see 5.5.2.6).
    Corresponds to label "W" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Installation, Signal Intelligence, Stability Operations, 
    EMS Units, EMS equipment and incidents, EMS installations
    Tactical Graphics: Points, Lines, Areas, Nuclear, Bio/Chem
    Length: 16
    @var {string} ? public
    */
    this.dateTimeGroup1;

    /**
    A text modifier for units, equipment, and installations that displays DTG format:
    DDHHMMSSZMONYYYY or O/O for an order(see 5.5.2.6).
    Corresponds to label "W1" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Not used
    Tactical Graphics: Points, Lines, Areas, Nuclear, Bio/Chem
    Length: 16
    @var {string} ? public
    */
    this.dateTimeGroup2;

    /**
    A text modifier that displays the minimum,
    maximum, and/or specific altitude (in feet or
    meters in relation to a reference datum), flight
    level, or depth (for submerged objects in feet
    below sea level). See 5.5.2.5 for content.  Contains
    an array of numbers representing altitude values.  This
    array may contain a single value (used mostly by units to display
    altitude as a label or it may be used to contain
    multiple values for specific graphics that may contain
    min/max altitudes or multiple altitudes for different sections
    of the graphic. See page 669/1170 of MIL-STD-25252C for example
    of how this modifier is used.
    Corresponds to label "X" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Installation, Stability Operations, 
    EMS Units, EMS equipment and incidents, EMS installations
    Tactical Graphics: Points, Lines, Areas, Nuclear, Bio/Chem
    Length: 14
    @var {Array} ? public
    */
    this.altitudeDepth = [];

    /**
    A text modifier that displays a graphic's location
    in degrees, minutes, and seconds (or in UTM or
    other applicable display format).
    Conforms to decimal
    degrees format:
    xx.dddddhyyy.dddddh
    where
    xx = degrees latitude
    yyy = degrees longitude
    .ddddd = decimal degrees
    h = direction (N, E, S, W)
    Corresponds to label "Y" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Installation, Signal Intelligence, Stability Operations, 
    EMS Units, EMS equipment and incidents, EMS installations
    Tactical Graphics: Points, Lines, Areas, Boundary Lines, Nuclear, Bio/Chem
    Length: 19
    @var {string} ? public
    */
    this.location;

    /**
    A text modifier for units and equipment that displays a velocity as set forth
    in MIL-STD-6040. Takes in a string representing the speed.
    Corresponds to label "Z" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Equipment, Stability Operations, 
    EMS Units, EMS equipment and incidents
    Tactical Graphics: Not used
    Length: 8
    @var {string} ? public
    */
    this.speed;

    /**
    A text modifier for units; indicator is contained inside the frame (see figures 2
    and 3); contains the name of the special C2 Headquarters. Takes in a string.
    Corresponds to label "AA" in the MIL-STD-2525C.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Units, Signal Intelligence
    Tactical Graphics: Not used
    Length: 9
    @var {string} ? public
    */
    this.specialC2Headquarters;


    /**
    For Tactical Graphics
    A numeric modifier that displays a minimum,
    maximum, or a specific distance (range, radius,
    width, length, etc.), in meters.
    0 - 999,999 meters. Contains an array of numbers.
    Corresponds to label "AM" in the MIL-STD-2525C.
    See page 669/1170 of MIL-STD-25252C for example
    of how this modifier is used.
    <br/>
    The order of values passed into AM depends on how they
    are specified in the MIL-STD-2525C.  AM = index 0, AM1 = index 1,
    AM2 = index 2...AMn = index n.  For instance in MIL-STD-2525C, 
    the rectangular target specifies two values, AM for width and AM1 
    for length.  Your array should be formated [AM, AM1].  If you were building a rectangular 
    target 300 meters in width and 800 meters in length, you would create an 
    array that looks like this: [300, 800]. 
    <br/>
    Valid for the following categories of graphics:  
    Warfighting Symbols: Not used
    Tactical Graphics: Points, Lines, Areas
    Length: 6
    @var {Array} ? public
    */
    this.distance = [];

    /**
    For Tactical Graphics
    A numeric modifier that displays an angle
    measured from true north to any other line in
    degrees.  Contains an array of numbers.
    Corresponds to label "AN" in the MIL-STD-2525C.
    0 - 359 degrees.       
    See page 669/1170 of MIL-STD-25252C for example
    of how this modifier is used.
    Valid for the following categories of graphics:  
    Warfighting Symbols: Not used
    Tactical Graphics: Points, Lines, Areas
    Length: 3
    @var {Array} ? public
    */
    this.azimuth = [];

    /**
    Gets/Sets the fill color of the graphic (if it has a fill).  Takes in
    a string representing the hex ARGB color value (e.g. 7700000FF)
    @var {string} ? public
    */
    this.fillColor;

    /**
    Gets/Sets the line color of the graphic or the frame of a single point graphic. 
    Takes in a string representing the hex ARGB color value (e.g. 7700000FF)
    @var {string} ? public
    */
    this.lineColor;

    /**
    Sets the offset for centering custom single point icons on an anchor point.  
	This can be specified by a fractional component of the icon or by pixels insets 
	in relation to the lower left corner of the icon depending on the value of xUnits.  
	This property will not affect MIL-STD-2525 graphics as they are positioned correctly 
	already.  By default, a custom icon's xOffset will be .5 and set to fraction.  Only 
	applies to basic points.
	@var {float} ? public float
    */
    this.xOffset;

    /**
    Sets how the graphic will use the xOffset modifier.  This value should be either 
	CoreMapAPI.UNITS_FRACTION, CoreMapAPI.UNITS_PIXELS, or CoreMapAPI.UNITS_INSET_PIXELS. 
	If the value is fraction, it indicates the xOffset value is a fraction of the icon. 
	If the value is pixels, it indicates the x value in pixels from the left of the icon. 
	A value of insetPixels indicates the indent from the right edge of the icon. 
	Only applies to basic points.
	@var {string} ? public
	*/
    this.xUnits;

    /**
    Sets the offset for centering custom single point icons on an anchor point.  
	This can be specified by a fractional component of the icon or by pixels 
	insets in relation to the lower left corner of the icon depending on the value 
	of yUnits.  This property will not affect MIL-STD-2525 graphics as they are 
	positioned correctly already.  By default, a custom icon's xOffset will be .5 
	and set to fraction.  Only applies to basic points.
	@var {float} ? public float
    */
    this.yOffset;

    /**
    Sets how the graphic will use the yOffset modifier.  This value should be either 
	CoreMapAPI.UNITS_FRACTION, CoreMapAPI.UNITS_PIXELS, or CoreMapAPI.UNITS_INSET_PIXELS.  
	If the value is fraction, it indicates the xOffset value is a fraction of the icon. 
	If the value is pixels, it indicates the y value in pixels from the bottom of the icon. 
	A value of insetPixels indicates the indent from the top edge of the icon.  
	Only applies to basic points.
	@var {string} ? public
	*/
    this.yUnits;

    /**
    Makes a basic line made out of this image.
    */
    this.lineIconURL;

    /**
    Fills a polygon with this image.
    */
    this.fillIconURL;

    /** 
	Changes the thickness for the lines
	*/
    this.lineThickness;

    /**
	Sets the permanent rotation of the graphic.  If this is set the icon will always point
	in this direction.  Can be between -360 to 360.  If out of bounds it will reset to undefined.
	*/
    this.heading;

}

/**
View defines a set of properties to give the 3D map a specific view to tightly control how the camera is placed in the 3D space.
@class View
*/

function View() {
    /**
    Latitude value in degrees decimal format
    @var {float} ? public float
    */
    this.latitude;
    /**
    Longitude value in degrees decimal format
    @var {float} ? public float
    */
    this.longitude;
    /**
    Altitude value in meters
    @var {int} ? public
    */
    this.altitude;
    /**
    Heading or direction to face the camera view in degres 0-360
    @var {int} ? public
    */
    this.heading;
    /**
    Angle to tilt the camera view 0-360
    @var {int} ? public
    */
    this.tilt;
    /**
    Altitude mode to use to measure the altitude of the camera.  Use CoreMapAPI.ALTITUDE _ABSOLUTE or CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
    @var {string} ? public
    */
    this.altitudeMode;
}

/**
CoreMapAPI is the deprecated Command Web API library.  This library was left in to
remain compatible with the Command Web/CPCE v1 widgets for Mission Command.  The library does not make
use of new capabilities available in the CPCE v2 library.  Only use this library if
you have an old widget capable of running in the CPCE v1 environment but cannot upgrade
to the CPCE v2 library.
*/
var CoreMapAPI = (function () {


    widgetEventingController = new Ozone.eventing.Widget('rpc_relay.uncompressed.html');
    var map3DmapEventHash = new CoreHash(),
        map3DdataEventHash = new CoreHash(),
        map3DdrawEventHash = new CoreHash(),
        publishChannelName = "Bcw.Map.Broadcast",
        boundingBox = {},
        approximateScale = 0,
        mapCenter = {};


    function handleMapEvent(sender, event) {
        var evtMessage = JSON.parse(event),
            callbacks = map3DmapEventHash.getItem(evtMessage.type),
            len,
            i;

        if (callbacks !== null && callbacks !== undefined) {
            len = callbacks.length;
            for (i = 0; i < len; i += 1) {
                if (callbacks[i] !== null) {
                    callbacks[i](evtMessage);
                }
            }
        }
        if (evtMessage.type === "mapMove" || evtMessage.type === "mapReady") {
            boundingBox = {
                left: evtMessage.eventData.left,
                bottom: evtMessage.eventData.bottom,
                right: evtMessage.eventData.right,
                top: evtMessage.eventData.top
            };
            approximateScale = evtMessage.eventData.scale;
            mapCenter = {
                lat: evtMessage.eventData.lat,
                lon: evtMessage.eventData.lon
            };
        }
    }

    function handleDrawEvent(sender, event) {
        var evtMessage = JSON.parse(event),
            callbacks = map3DdrawEventHash.getItem(evtMessage.type),
            len,
            i,
            callback;

        if (callbacks !== null && callbacks !== undefined) {
            len = callbacks.length;
            for (i = 0; i < len; i += 1) {
                callback = callbacks[i];
                if (callback !== undefined && callback !== null) {
                    if (callback.id !== undefined && callback.id !== null && callback.id !== "undefined" && callback.id !== "null") {
                        if (evtMessage.eventData.id === callback.id) {
                            callback.callback(evtMessage);
                        }
                    } else {
                        callback.callback(evtMessage);
                    }
                }
            }
        }
    }

    function handleDataEvent(sender, event) {
        var evtMessage = JSON.parse(event),
            callbacks = map3DdataEventHash.getItem(evtMessage.type),
            len,
            i,
            callback;

        if (callbacks !== null && callbacks !== undefined) {
            len = callbacks.length;
            for (i = 0; i < len; i += 1) {
                callback = callbacks[i];
                if (callback !== undefined && callback !== null) {
                    if (callback.id !== undefined && callback.id !== null && callback.id !== "undefined" && callback.id !== "null") {
                        if (evtMessage.eventData.id === callback.id) {
                            callback.callback(evtMessage);
                        }
                    } else {
                        callback.callback(evtMessage);
                    }
                }
            }
        }
    }

    // Event channel to recieve map events
    widgetEventingController.subscribe("core.api.map.eventing", handleMapEvent);
    // Event channel to receive graphics events
    widgetEventingController.subscribe("core.api.graphics.eventing", handleDataEvent);
    // Event channel to receive graphic drawing events
    widgetEventingController.subscribe("core.api.graphics.drawing", handleDrawEvent);

    function publishMessage(message) {

        widgetEventingController.publish(publishChannelName, message);
    }

    return {
        /** 
        3D Shape type to be used when creating a cake
        @var {string} ? public
        */
        SHAPE3D_CAKE: 'CAKE-----------',
        /** 
        3D Shape type to be used when creating a route
        @var {string} ? public
        */
        SHAPE3D_ROUTE: 'ROUTE----------',
        /** 
        3D Shape type to be used when creating a cylinder
        @var {string} ? public
        */
        SHAPE3D_CYLINDER: 'CYLINDER-------',
        /** 
        3D Shape type to be used when creating an orbit
        @var {string} ? public
        */
        SHAPE3D_ORBIT: 'ORBIT----------',
        /** 
        3D Shape type to be used when creating a polygon
        @var {string} ? public
        */
        SHAPE3D_POLYGON: 'POLYGON--------',
        /** 
        3D Shape type to be used when creating a radarc
        @var {string} ? public
        */
        SHAPE3D_RADARC: 'RADARC---------',
        /** 
        3D Shape type to be used when creating a polyarc
        @var {string} ? public
        */
        SHAPE3D_POLYARC: 'POLYARC--------',
        /** 
        3D Shape type to be used when creating a track
        @var {string} ? public
        */
        SHAPE3D_TRACK: 'TRACK----------',

        /** 
        Altitude mode that clamps object to ground regardless of the elevation at that given point
        @var {string} ? public
        */
        ALTITUDE_CLAMP_TO_GROUND: 'clampToGround',

        /** 
        Altitude mode that measures elevation above the underlying terrain (AGL)
        @var {string} ? public
        */
        ALTITUDE_RELATIVE_TO_GROUND: 'relativeToGround',
        /** 
        Altitude mode that measures elevation above mean sea level (MSL)
        @var {string} ? public
        */
        ALTITUDE_ABSOLUTE: 'absolute',
        /** 
        Event Dispatched when 3D map location and/or scale changes
        @var {string} ? public
        */
        MAP_MOVE: 'mapMove',
        /** 
        Event Dispatched when 3D map is clicked.  No map click event will fire if the cursor is in select mode and a graphic is clicked.
        @var {string} ? public
        */
        MAP_CLICK: 'mapClick',
        /** 
        Event Dispatched when 3D map is double clicked.   No map double click event will fire if the cursor is in select mode and a graphic is double clicked.
        @var {string} ? public
        */
        MAP_DOUBLE_CLICK: 'mapDoubleClick',
        /** 
        Event Dispatched when a new map is opened and the Globe has successfully initialized.
        @var {string} ? public
        */
        MAP_READY: 'mapReady',
        /** 
        Event Dispatched when a map is closed.
        @var {string} ? public
        */
        MAP_CLOSE: 'mapClose',
        /** 
        Event Dispatched when an graphic is clicked. This event is only fired when the map cursor mode is set to CoreMapAPI.CURSOR_MODE_SELECT (Arrow Cursor).
        @var {string} ? public
        */
        GRAPHIC_CLICK: 'graphicClick',
        /** 
        Event Dispatched when an graphic is double clicked. This event is only fired when the map cursor mode is set to CoreMapAPI.CURSOR_MODE_SELECT (Arrow Cursor).
        @var {string} ? public
        */
        GRAPHIC_DOUBLE_CLICK: 'graphicDoubleClick',
        /** 
        Event Dispatched when a property or location of a graphic is updated on the map.  This event is only fired when the map cursor mode is set to CoreMapAPI.CURSOR_MODE_SELECT.
        @var {string} ? public
        */
        GRAPHIC_UPDATE: 'graphicUpdate',
        /**
        Notifies the offset for anchor should be specified in pixels from the right or top in pixels
        */
        UNITS_INSET_PIXELS: "insetPixels",
        /**
        Notifies the offset for anchor should be specified in pixels from the left or bottom in pixels
        */
        UNITS_PIXELS: "pixels",
        /**
        Notifies the offset for anchor should be specified in a fraction from the left bottom.
        */
        UNITS_FRACTION: "fraction",

        /**
        Set map location to a given latitude and longitude and a specified range (3D camera distance from the ground in meters)
        @function 
        @param {float}   lat - latitude value in degrees decimal format i.e. 48.2345
        @param {float}   lon - longitude value in degrees decimal format i.e. -127.5672
        @param {float}   range - value of the view distance between the 3D camera and the ground in meters
        */
        goToLocationWithRange: function (lat, lon, range) {
            var message = "goToLocationWithRange(" + lat + "," + lon + "," + range + ")";
            publishMessage(message);
        },


        /**
        Returns an object representing the center coordinates of the map 
        @function 
        @returns {object} object with two properties lat and lon representing the center of the map i.e. (lat:34.56633, lon:44.5812)
        */
        getMapCenter: function () {
            return mapCenter;
        },

        /**
        Returns a bounding box representing the visible extents of the map view in degrees decimal
        @function
        @returns {object} with four properties representing the visible extents of the map - left,bottom,right,top i.e. (left:34.56633, bottom:44.5812, right:36.2342, top:46.7839)
        */
        getMapExtents: function () {
            return boundingBox;
        },

        /**
        Set the visibility of a collection of graphics in a batch process.  
        This enables the map to efficiently process thousands of visibility changes in a batch.
        This should be used in place of setVisibility anytime a collection of graphics' visibility needs to be set.
        Visibility value of true and false can be different for each graphic allowing graphics to be shown and hidden in one call.
        @function
        @param {array} batch - Array of visibility objects which contain two properties - id and visibility.  [(id:graphicIdHere,visibility:true),(id:anotherGraphicIdHere,visibility:false)]
        */
        setVisibilityBatch: function (batch) {
            var batchObject = {},
                batchString,
                message;
            batchObject.batch = batch;
            batchString = JSON.stringify(batchObject);
            message = "setVisibilityBatch('" + escape(batchString) + "')";
            publishMessage(message);
        },

        /**
        Returns the approximate map scale.  Scale is approximated using the Google Earth camera altitude because Google Earth does not support a concept of map scale natively
        @function 
        @returns approximate map scale
        */
        getApproximateScale: function () {
            return approximateScale;
        },

        /**
        Set map location to a given latitude and longitude and a specified map scale (i.e. 1:50,000)
        @function
        @param {float}   lat - latitude value in degrees decimal format i.g. 48.2345
        @param {float}   lon - longitude value in degrees decimal format i.g. -127.5672
        @param {int} scale - value of the desired map scale as an integer i.g. For 1:50,000 scale should be set to 50000.   
        Scale is approximated using the Google Earth camera altitude because Google Earth does not support a concept of map scale natively
        */
        goToLocationWithScale: function (lat, lon, scale) {
            var message = "goToLocationWithScale(" + lat + "," + lon + "," + scale + ")";
            publishMessage(message);

        },

        /**
        Set map location to a given latitude and longitude 
        @function
        @param {float}   lat - latitude value in degrees decimal format i.g. 48.2345
        @param {float}   lon - longitude value in degrees decimal format i.g. -127.5672
        */
        goToLocation: function (lat, lon) {
            var message = "goToLocation(" + lat + "," + lon + ")";
            publishMessage(message);

        },

        /**
        Adds a KML or KMZ document to the map via URL. Content of the KML file will display on the map, but will not be listed in the content tree.
        @function
        @param {string} url - Fully qualified URL to the KML or KMZ document.  Relative paths will not be processed by the Google Earth Plugin. A fully-qualified URL must be provided i.e http://myserver/kml/kmlsample.kmz.
        @param {string} name - Display name for the document in the map layer management tree
        @see CoreMapAPI.removeKml
        */
        addKml: function (url, name) {
            var message = 'addKml("' + url + '","' + name + '")';
            publishMessage(message);

        },


        /**
        Removes a KML or KMZ document from the map which was added via the addKml or addKmlFromString method. 
        @function
        @param {string} url - Fully-qualified URL to the KML or KMZ document.  In the case of removing KML added via the addKmlFromString method, pass the id used in place of a URL.
        @see CoreMapAPI.addKml
        @see CoreMapAPI.addKmlFromString
        */
        removeKml: function (url) {
            var message = 'removeKml("' + url + '")';
            publishMessage(message);

        },

        /**
        Adds KML to the map from a KML formatted string. 
        @function
        @param {string} kmlString - KML formatted string
        @param {string} name - Display name for the kml in the map layer management tree
        @param {string} id - Unique id for the kml.  Use this id for the URL parameter in the removeKml function
        @see CoreMapAPI.removeKml
        */
        addKmlFromString: function (kmlString, name, id) {
            var message;
            kmlString = escape(kmlString);

            message = 'addKmlFromString("' + kmlString + '","' + name + '","' + id + '")';
            publishMessage(message);
        },

        /**
        Adds KML to the map from a KML formatted string that will be located within an overlay in the map content tree.  
        The KML string should NOT be a complete KML document with a Document node, but rather a well formed KML fragment 
        such as a placemark or folder when multiple placemarks are neccessary.  This KML fragment will be treated as 
        other graphics on an overly and can be removed by calling CoreMapAPI.removeGraphic
        @function
        @param {string} kmlString - KML formatted string
        @param {string} name - Display name for the KML in the map layer management tree
        @param {string} id - Unique id for the KML
        @param {string} overlayId - Unique id for the overlay to which the KML will be added
        @param {string} referenceLat - Latitude value in decimal degrees for a reference point to enable navigation to the contents of the KML fragment from the map content tree
        @param {string} referenceLon - Longitude value in decimal degrees for a reference point to enable navigation to the contents of the KML fragment from the map content tree
		@param {string} iconUrl - a url to an image that will display on the data explorer for this KML
        @see CoreMapAPI.removeGraphic
        */
        addKmlStringToOverlay: function (kmlString, name, id, overlayId, referenceLat, referenceLon, iconUrl) {
            var message;

            kmlString = escape(kmlString);
            message = 'addKmlStringToOverlay("' + kmlString + '","' + name + '","' + id + '","' + overlayId + '",' + referenceLat + ',' + referenceLon + ',' + '"' + iconUrl + '")';
            publishMessage(message);
        },

        /**
        Adds a WMS layer to the map via URL. Content of the file will display on the map, and will be listed in the content tree
        @function
        @param string url - Fully qualified URL to the GIS server. Relative paths will not be processed by the Google Earth Plugin.
        @param string name - Name of layer hosted on GIS server to be rendered on map
        @returns void
        */
        addWms: function (url) {
            var message = 'addWms("' + url + '")';
            publishMessage(message);

        },

        /**
        Removes a WMS layer on the map via URL. Content of the file will remove from the map, and will be removed from the content tree
        @function
        @param string url - Fully qualified URL to the GIS server. Relative paths will not be processed by the Google Earth Plugin
        @returns void
        */
        removeWms: function (name) {
            var message = 'removeWms("' + name + '")';
            publishMessage(message);

        },


        /**
        Add a point to an overlay for display on the map.  
        @function 
        @param {string} name - Display name for the point
        @param {string} id - Unique Id of the point
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay to which the point will be addedd
        @param {float}   lat - latitude value in degrees decimal format i.e. 48.2345
        @param {float}   lon - longitude value in degrees decimal format i.e. -127.5672
        @param {float}   altitude - altitude value in meters
        @param {string} description - HTML formatted string to be displayed in the info popup for the point
        @param {string} iconURL - URL for the image to use as the point icon.  If this value is null, undefined, or an empty string the map will use a default icon
        @param {string} altitudeMode - Constant value of CoreMapAPI.ALTITUDE_ABSOLUTE for mean sea level or MSL, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND for above ground level or AGL, 
        or CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND to ignore the altitude and display the point at ground level regardless of the underlying elevation
        @param {Modifiers} modifiers - a Modifiers object populated with the correct xOffset, yOffset, xUnits, and yUnits to make the icon anchor in the correct location.
        @returns id of point
	
        */
        addPoint: function (name, id, sourceId, overlayId, lat, lon, altitude, description, iconURL, altitudeMode, modifiers) {
            var comString,
                modString,
                modifiersObject,
                message;

            comString = '"' + name + '",';
            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += lat + ',';
            comString += lon + ',';
            comString += altitude + ',';
            comString += '"' + escape(description) + '",';
            comString += '"' + iconURL + '",';
            comString += '"' + altitudeMode + '"';

            if (modifiers !== null && modifiers !== undefined) {
                modifiersObject = {};
                modifiersObject.modifiers = modifiers;
                modString = JSON.stringify(modifiersObject);
                modString = escape(modString);
                comString += ',"' + modString + '"';
            }

            message = 'addPoint(' + comString + ')';

            publishMessage(message);
            return id;

        },
        /**
        Updates an existing point on an overlay for display on the map.  
        @function
        @param {string} name - Display name for the point
        @param {string} id - Unique Id of the point
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay to which the point will be updated
        @param {float}   lat - latitude value in degrees decimal format i.e. 48.2345
        @param {float}   lon - longitude value in degrees decimal format i.e. -127.5672
        @param {float}   altitude - altitude value in meters
        @param {string} description - HTML formatted string to be displayed in the info popup for the point
        @param {string} iconURL - URL for the image to use as the point icon.  If this value is null, undefined, or an empty string the map will use a default icon
        @param {string} altitudeMode - Constant value of CoreMapAPI.ALTITUDE_ABSOLUTE for mean sea level or MSL, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND for above ground level or AGL, 
        or CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND to ignore the altitude and display the point at ground level regardless of the underlying elevation
        @param {Modifiers} modifiers - a Modifiers object populated with the correct xOffset, yOffset, xUnits, and yUnits to make the icon anchor in the correct location.
        @returns id of point
	
        */
        updatePoint: function (name, id, sourceId, overlayId, lat, lon, altitude, description, iconURL, altitudeMode, modifiers) {
            this.addPoint(name, id, sourceId, overlayId, lat, lon, altitude, description, iconURL, altitudeMode, modifiers);

        },

        /**
        Add a batch of points to an overlay for display on the map.  Adding points in batch improves performance and can support thousands of items in a single call.  
        @function
        @param {array} batch - Array of point objects.  The batch array should be formatted as follows with each object in the array representing one point.  This batch array only contains two points for simple deomnstration:
        var batch = [(name:"Helicopter 1", id:"e8403351-8478-41cb-994e-0c98ba1e896b", sourceId:"fakeId", overlayId:"overlay id from addOverlay", lat:37.6543, lon:44.5876, altitude:1000, description: "This is a great description!",url: "http://cdn1.iconfinder.com/data/icons/mapicons/icons/helicopter.png", altitudeMode:CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND, visibility:true, modifiers:null},{name:"Helicopter 2", id:"ada03a6d-00b1-4275-8e42-1fd3f94c9314", sourceId:"fakeId", overlayId:"overlay id from addOverlay", lat:38.6543, lon:42.5876, altitude:3500, description: "This is a great description!",url: "http://cdn1.iconfinder.com/data/icons/mapicons/icons/helicopter.png", altitudeMode:CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND, visibility:true, modifiers:null)]
        */
        addPointBatch: function (batch) {
            var len = batch.length,
                groupLengthMax = 1000,
                currentGroupLength = 0,
                comString = '',
                i,
                visibility = true,
                modifiersObject,
                modString,
                message;

            for (i = 0; i < len; i += 1) {

                if (currentGroupLength > 0) {
                    comString += ',';
                } else {
                    comString = '[';
                }

                comString += '{name:"' + batch[i].name + '",';
                comString += 'id:"' + batch[i].id + '",';
                comString += 'sourceId:"' + batch[i].sourceId + '",';
                comString += 'overlayId:"' + batch[i].overlayId + '",';
                comString += 'lat:' + batch[i].lat + ',';
                comString += 'lon:' + batch[i].lon + ',';
                comString += 'altitude:' + batch[i].altitude + ',';
                comString += 'description:"' + escape(batch[i].description) + '",';
                if (batch[i].hasOwnProperty("url")) {
                    comString += 'url:"' + batch[i].url + '",';
                } else if (batch[i].hasOwnProperty("iconURL")) {
                    comString += 'url:"' + batch[i].iconURL + '",';
                } else {
                    comString += 'url:"",';
                }
                comString += 'altitudeMode:"' + batch[i].altitudeMode + '"';

                if (batch[i].hasOwnProperty('visibility')) {
                    visibility = batch[i].visibility;
                }
                comString += ',visibility:"' + visibility + '"';
                if (batch[i].modifiers !== null && batch[i].modifiers !== undefined) {
                    modifiersObject = {};
                    modifiersObject.modifiers = batch[i].modifiers;
                    modString = JSON.stringify(modifiersObject);
                    modString = escape(modString);
                    comString += ',"modifiers":"' + modString + '"';
                }

                comString += '}';
                currentGroupLength += 1;
                if (currentGroupLength === groupLengthMax || i === (len - 1)) {
                    comString += ']';
                    message = 'addPointBatch(' + comString + ')';
                    publishMessage(message);
                    comString = '';
                    currentGroupLength = 0;
                }
            }
        },

        /**
        Add a multipoint MIL-STD-2525 symbol to an overlay for display on the map.  
        @function 
        @param {string} name - Display name for the symbol
        @param {string} id - Id of the symbol
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the map overlay to which the symbol will be added
        @param {string} symbolCode - 15 character MIL-STD-2525 symbol code
        @param {string} coordinates - Collection of coordinates for a multipoint MIL-STD-2525 symbol in string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} description - HTML formatted string to be displayed in the info popup for the symbol
        @param {Modifiers} modifiers - Modifiers object containing the labels and properties of the symbol being added.
        @param {boolean} visibility - Optional - NEW in 13.0.4 - Sets default visibility of the item, true for visibile false for hidden.  If no value is supplied, the default is true.
        @param {string} altitudeMode - Optional - NEW in 13.0.4 - Constant value of CoreMapAPI.ALTITUDE_ABSOLUTE for above sea level or MSL, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND for above ground level or AGL, or CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND to ignore the altitude and display the point at ground level regardless of the underlying elevation
        @returns id of the MIL-STD-2525 symbol
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        @see Modifiers

        */
        addMilStdMultiPoint: function (name, id, sourceId, overlayId, symbolCode, coordinates, description, modifiers, visibility, altitudeMode) {

            var comString,
                modifiersObject,
                modString,
                message;

            if (visibility === undefined || visibility === null) {
                visibility = true;
            }

            comString = '"' + name + '",';
            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += '"' + symbolCode + '",';
            comString += '"' + coordinates + '",';
            comString += '"' + escape(description) + '"';

            if (modifiers !== null && modifiers !== undefined) {
                modifiersObject = {};
                modifiersObject.modifiers = modifiers;
                modString = JSON.stringify(modifiersObject);
                comString += ',"' + escape(modString) + '"';
            } else {
                comString += ',null';
            }

            if (visibility !== true && visibility !== false) {
                visibility = true;
            }
            comString += ',' + visibility;

            if (altitudeMode === null || altitudeMode === undefined) {
                altitudeMode = CoreMapAPI.ALTITUDE_ABSOLUTE;
            }
            comString += ',"' + altitudeMode + '"';

            message = 'addMilStdSymbol(' + comString + ')';
            publishMessage(message);
            return id;
        },

        /**
        Update an existing multipoint MIL-STD-2525 symbol for display on the map.  
        @function
        @param {string} name - Display name for the symbol
        @param {string} id - Id of the symbol
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the map overlay to which the symbol will be added
        @param {string} symbolCode - 15 character MIL-STD-2525 symbol code
        @param {string} coordinates - Collection of coordinates for a multipoint MIL-STD-2525 Symbol in string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} description - HTML formatted string to be displayed in the info popup for the symbol
        @param {Modifiers} modifiers - Modifiers object containing the MIL-STD-2525 labels and properties of the graphic being updated.
        */
        updateMilStdMultiPoint: function (name, id, sourceId, overlayId, symbolCode, coordinates, description, modifiers) {
            this.addMilStdMultiPoint(name, id, sourceId, overlayId, symbolCode, coordinates, description, modifiers);
        },

        /**
        Add a single point MIL-STD-2525 symbol to an overlay for display on the map.  
        @function
        @param {string} name - Display name for the symbol
        @param {string} id - Unique id of symbol
        @param {string} sourceId - Constant id of the data source
        @param {string} overlayId - Id of the map overlay to add the symbol to
        @param {string} symbolCode - 15 character MIL-STD-2525 symbol code
        @param {float}   lat - Latitude in degrees decimal.  
        @param {float}   lon - Longitude in degrees decimal.  
        @param {float}   altitude - Altitude in meters. 
        @param {string} description - HTML formatted string to be displayed in the info popup for the symbol
        @param {string} altitudeMode - Conmstant value of CoreMapAPI.ALTITUDE_ABSOLUTE for above sea level or MSL, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND for above ground level or AGL, and CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND to ignore the altitude and display the point at ground level regardless of the underlyign elevation
        @param {Modifiers} modifiers - MIL-STD-2525 labels and properties of the graphic being added.  Use an instance of the Modifiers class and populate the modfiers for use.  All modifiers are optional and default values are povided for unused modifiers.
        @returns id of the MIL-STD-2525 symbol
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        @see Modifiers
        */
        addMilStdPoint: function (name, id, sourceId, overlayId, symbolCode, lat, lon, altitude, description, altitudeMode, modifiers) {

            var comString,
                modifiersObject,
                modString,
                message;

            comString = '"' + name + '",';
            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += '"' + symbolCode + '",';
            comString += +lat + ',';
            comString += +lon + ',';
            comString += +altitude + ',';
            comString += '"' + escape(description) + '",';
            comString += '"' + altitudeMode + '"';

            if (modifiers !== null && modifiers !== undefined) {
                modifiersObject = {};
                modifiersObject.modifiers = modifiers;
                modString = JSON.stringify(modifiersObject);
                modString = escape(modString);
                comString += ',"' + modString + '"';
            }

            message = 'addMilStdPoint(' + comString + ')';
            publishMessage(message);
            return id;
        },

        /**
        Add a batch of MIL-STD-2525 points to an overlay for display on the map.  Adding points in batch improves performance and can support thousands of items in a single call.  
        @function
        @param {array} batch - Array of MIL-STD-2525 point objects.  The batch array should be formatted as follows with each object in the array representing one MIL-STD-2525 point.  This batch array only contains two points for simple deomnstration:
        var batch = [(name:"Infantry Unit 1", id:"cbe28aca-1fde-475c-8b60-11eeda1542fb", sourceId:"fakeId", overlayId:"overlay id from addOverlay",symbolCode:"SFGPUCI--------", lat:37.6543, lon:44.5876, altitude:1000, description: "This is a great description!", altitudeMode:CoreMapAPI.ALTITUDE_ABSOLUTE,modifiers:modifiersObject,visibility:true},{name:"Infantry Unit 2", id:"c4b2b62c-38d1-498d-a85f-aebdcdb8b647", sourceId:"fakeId", overlayId:"overlay id from addOverlay",symbolCode:"SFGPUCI--------", lat:38.6543, lon:42.5876, altitude:3500, description: "This is a great description!", altitudeMode:CoreMapAPI.ALTITUDE_ABSOLUTE,modifiers:modifiersObject,visibility:false)]
        */
        addMilStdPointBatch: function (batch) {

            var len = batch.length,
                groupLengthMax = 1000,
                currentGroupLength = 0,
                comString = '',
                i,
                visibility = true,
                modifiersObject,
                modString,
                message;

            for (i = 0; i < len; i += 1) {

                if (currentGroupLength > 0) {
                    comString += ',';
                } else {
                    comString = '[';
                }
                comString += '{name:"' + escape(batch[i].name) + '",';
                comString += 'id:"' + batch[i].id + '",';
                comString += 'sourceId:"' + batch[i].sourceId + '",';
                comString += 'overlayId:"' + batch[i].overlayId + '",';
                comString += 'symbolCode:"' + batch[i].symbolCode + '",';
                comString += 'lat:' + batch[i].lat + ',';
                comString += 'lon:' + batch[i].lon + ',';
                comString += 'coordinates:"' + batch[i].lon + ',' + batch[i].lat + '",';
                comString += 'altitude:' + batch[i].altitude + ',';
                comString += 'description:"' + escape(batch[i].description) + '",';
                comString += 'altitudeMode:"' + escape(batch[i].altitudeMode) + '"';

                if (batch[i].hasOwnProperty('visibility')) {
                    visibility = batch[i].visibility;
                }
                comString += ',visibility:' + visibility;
                if (batch[i].modifiers !== undefined && batch[i].modifiers !== null) {
                    modifiersObject = {};
                    modifiersObject.modifiers = batch[i].modifiers;
                    modString = JSON.stringify(modifiersObject);
                    comString += ',modifiers:"' + escape(modString) + '"';
                }
                comString += '}';
                currentGroupLength += 1;
                if (currentGroupLength === groupLengthMax || i === (len - 1)) {
                    comString += ']';
                    message = 'addMilStdPointBatch(' + comString + ')';
                    publishMessage(message);
                    comString = '';
                    currentGroupLength = 0;
                }
            }

        },

        /**
        Add a batch of multipoint MIL-STD-2525 graphics to an overlay for display on the map.  Adding in batch improves performance and can support hundreds of items in a single call.  
        @function
        @param {array} batch - Array of multipoint MIL-STD-2525 graphics.  The batch array should be formatted as follows with each object in the array representing one multipoint MIL-STD-252 graphic.  This batch array only contains two graphics for simple deomnstration:
        var batch = [(name:"Symbol 1", id:"cbe28aca-1fde-475c-8b60-11eeda1542fb", sourceId:"fakeId", overlayId:"overlay id from addOverlay",symbolCode:"GFFPACNI------X", coordinates:"38.902285,-77.047482 38.904338,-77.038583 38.900516,-77.039496 38.898919,-77.043032", description: "This is a great description!",altitudeMode:CoreMapAPI.ALTITUDE_ABSOLUTE,modifiers:modifiersObject,visibility:true},{name:"Symbol 2", id:"c4b2b62c-38d1-498d-a85f-aebdcdb8b647", sourceId:"fakeId", overlayId:"overlay id from addOverlay",symbolCode:"GFFPACNI------X", coordinates:"38.892758,-77.045713 38.893215,-77.034191 38.899489,-77.037727 38.895896,-77.048908", description: "This is a great description!", altitudeMode:CoreMapAPI.ALTITUDE_ABSOLUTE,modifiers:modifiersObject, visibility:false)]
        */
        addMilStdMultiPointBatch: function (batch) {

            var len = batch.length,
                altitudeMode,
                comString = '[',
                i,
                visibility = true,
                modifiersObject,
                modString,
                message;

            for (i = 0; i < len; i += 1) {
                if (i > 0) {
                    comString += ',';
                }

                comString += '{name:"' + batch[i].name + '",';
                comString += 'id:"' + batch[i].id + '",';
                comString += 'sourceId:"' + batch[i].sourceId + '",';
                comString += 'overlayId:"' + batch[i].overlayId + '",';
                comString += 'symbolCode:"' + batch[i].symbolCode + '",';
                comString += 'coordinates:"' + batch[i].coordinates + '",';
                comString += 'description:"' + escape(batch[i].description) + '"';
                visibility = true;
                if (batch[i].hasOwnProperty('visibility')) {
                    visibility = batch[i].visibility;
                }
                comString += ',visibility:' + visibility;
                if (batch[i].hasOwnProperty('altitudeMode')) {
                    altitudeMode = batch[i].altitudeMode;
                }
                comString += ',altitudeMode:"' + altitudeMode + '"';
                if (batch[i].modifiers !== undefined && batch[i].modifiers !== null) {
                    modifiersObject = {};
                    modifiersObject.modifiers = batch[i].modifiers;
                    modString = JSON.stringify(modifiersObject);
                    comString += ',modifiers:"' + escape(modString) + '"';
                }
                comString += '}';
            }
            comString += ']';
            message = 'addMilStdMultiPointBatch(' + comString + ')';
            publishMessage(message);
        },

        /**
        Update an existing single point MIL-STD-2525 symbol to an overlay for display on the map.  
        @function
        @param {string} name - Display name for the symbol
        @param {string} id - Unique id of symbol
        @param {string} sourceId - Constant id of the data source
        @param {string} overlayId - Id of the map overlay to which the symbol will be added
        @param {string} symbolCode - 15 character MIL-STD-2525 symbol code
        @param {float}   lat - Latitude in degrees decimal.  
        @param {float}   lon - Longitude in degrees decimal.  
        @param {float}   altitude - Altitude in meters. 
        @param {string} description - HTML formatted string to be displayed in the info popup for the symbol
        @param {string} altitudeMode - Conmstant value of CoreMapAPI.ALTITUDE_ABSOLUTE for above sea level or MSL, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND for above ground level or AGL, or CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND to ignore the altitude and display the point at ground level regardless of the underlyign elevation
        @param {Modifiers} modifiers - Modifiers object containing the MIL-STD-2525 labels and properties of the graphic being added.  Use an instance of the Modifiers class and populate the modfiers for use.  All modifiers are optional and default values are provided for unused modifiers.
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        @see Modifiers
        */
        updateMilStdPoint: function (name, id, sourceId, overlayId, symbolCode, lat, lon, altitude, description, altitudeMode, modifiers) {
            this.addMilStdPoint(name, id, sourceId, overlayId, symbolCode, lat, lon, altitude, description, altitudeMode, modifiers);
        },

        /**
        Creates an overlay container that groups data to be displayed on the map.  
        @function 
        @param {string} name - Display name for the overlay
        @param {string} id - Unique id for the overlay.  If the id provided is null, undefined, or an empty string an id will be generated.
        @param {string} parentId - Id of the overlay that will contain this overlay.  There is no limit to the nesting of overlays.  Use an empty String if this overlay should appear at the Root Level
        @param {boolean} editable - True if the overlay can be edited, false if the overlay is locked
        @param {string} description - String describing the overlay
        @param {string} treeIconUrl - Optional url for a custom icon in the map content tree.  If no URL is provided, a default icon will be used.
        @returns id of the newly created overlay.  If an id was provided when creating the overlay it will match this value.
        */
        addOverlay: function (name, id, parentId, editable, description, treeIconUrl) {
            var iconUrl = "",
                comString,
                message;

            if (treeIconUrl !== undefined && treeIconUrl !== null) {
                iconUrl = treeIconUrl;
            }
            if (parentId === null || parentId === "null") {

                parentId = '';
            }
            if (id === null || id === undefined || id.length === 0) {
                id = this.createGUID();
            }
            comString = '"' + name + '",';
            comString += '"' + id + '",';
            comString += '"' + parentId + '",';
            comString += editable.toString();
            comString += ',"' + escape(description) + '"';
            comString += ',"' + escape(iconUrl) + '"';
            message = 'addEffort(' + comString + ')';

            publishMessage(message);
            return id;
        },

        /**
        Removes an overlay container from the map and all of the child graphics and overlays contained by the overlay.
        @function
        @param {string} id - Id of the overlay to be removed.  Each overlay has a unique Id that is returned when the overlay is first created.
        @param {string} parentId - Id of the parent overlay if this overlay was added as a child of an existing overlay
        */
        removeOverlay: function (id, parentId, treeOnly) {
            if (treeOnly === undefined || treeOnly === null) {
                treeOnly = false;
            }
            var comString = '"' + id + '",',
                message;

            comString += '"' + parentId + '",';
            comString += treeOnly;

            message = 'removeEffort(' + comString + ')';
            publishMessage(message);
        },

        /**
        Add a line to an overlay for display on the map.  
        @function 
        @param {string} name - Display name for the line
        @param {string} id - Id of the line
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay to which the line will be added
        @param {string} coordinates - Collection of coordinates for a line in string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} description - HTML formatted string to be displayed in the info popup for the line
        @param {string} lineColor - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. '003366FF'.
        @param {float}   lineThickness - Float representing thickness of the line in pixels
        @param {string} altitudeMode - Value to determine how to calculate the alitude.  Options are defined as constants CoreMapAPI.ALTITUDE_ABSOLUTE, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND, CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND  
        @param {boolean} extrude - false by default.  If set to true the line will extend all the way to ground if at an alitude above ground level
        @param {object} modifiers - Optional - NEW in 13.0.4 - The options object allows for customizations to the polygon styling and editing permissions 
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        @returns id of the line
        */
        addLine: function (name, id, sourceId, overlayId, coordinates, description, lineColor, lineThickness, altitudeMode, extrude, modifiers) {
            var comString = '"' + name + '",',
                message,
                modString,
                modifiersObject;

            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += '"' + coordinates + '",';
            comString += '"' + escape(description) + '",';
            comString += '"' + lineColor + '",';
            comString += lineThickness + ",";
            comString += '"' + altitudeMode + '",';
            comString += extrude;

            if (modifiers !== null && modifiers !== undefined) {
                modifiersObject = {};
                modifiersObject.modifiers = modifiers;
                modString = JSON.stringify(modifiersObject);
                modString = escape(modString);
                comString += ',"' + modString + '"';
            }

            message = 'addLine(' + comString + ')';

            publishMessage(message);
            return id;
        },

        /**
        Update a line on an overlay for display on the map.  
        @function
        @param {string} name - Display name for the line
        @param {string} id - Id of the line
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay containing the line
        @param {string} coordinates - Collection of coordinates for a line in string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} description - HTML formatted string to be displayed in the info popup for the line
        @param {string} lineColor - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. 003366FF.
        @param {float}   lineThickness - float representing thickness of the line in pixels
        @param {string} altitudeMode - Value to determine how to calculate the alitude.  Options are defined as constants CoreMapAPI.ALTITUDE_ABSOLUTE, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND, CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND  
        @param {boolean} extrude - false by default.  If set to true the line will extend all the way to ground if at an alitude above ground level
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        */
        updateLine: function (name, id, sourceId, overlayId, coordinates, description, lineColor, lineThickness, altitudeMode, extrude) {
            this.addLine(name, id, sourceId, overlayId, coordinates, description, lineColor, lineThickness, altitudeMode, extrude);
        },

        /**
        Put the map into draw mode to draw a new line.  After receiving this call, the map will plot a point for the line each time the map is clicked and dispatch the drawComplete event on double click which will invoke the provided callback function.
        @function
        @param {function} drawCompleteCallback - Callback function that will be invoked after the line is drawn and the map is double clicked finishing the drawing of the symbol. The callback function should expect one parameter which is the drawComplete event with the coordinates of the drawn line. 
        @param {string} name - Display name for the line
        @param {string} id - Id of the line
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay containing the line
        */
        drawLine: function (drawCompleteCallback, name, id, sourceId, overlayId) {

            var comString = '"' + name + '",',
                message;

            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '"';

            message = 'drawLine(' + comString + ')';

            publishMessage(message);
            //map3DdrawEventHash.setItem(id, drawCompleteCallback);
            this.registerDrawingListener("drawComplete", drawCompleteCallback, id);
        },

        /**
        Put the map into draw mode to draw a new polygon.  After receiving this call, the map will plot a point for the polygon each time the map is clicked and dispatch the drawComplete event on double click which will invoke the provided callback function.
        @function
        @param {function} drawCompleteCallback - Callback function that will be invoked after the line is drawn and the map is double clicked finishing the drawing of the symbol. The callback function should expect one parameter which is the drawComplete event with the coordinates of the drawn line. 
        @param {string} name - Display name for the polygon
        @param {string} id - Id of the polygon
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay containing the polygon
        */
        drawPolygon: function (drawCompleteCallback, name, id, sourceId, overlayId) {

            var comString = '"' + name + '",',
                message;

            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '"';

            message = 'drawPolygon(' + comString + ')';

            publishMessage(message);
            //map3DdrawEventHash.setItem(id, drawCompleteCallback);
            this.registerDrawingListener("drawComplete", drawCompleteCallback, id);
        },

        /**
        Put the map into draw mode to draw a multipoint MIL-STD-2525 symbol.  After receiving this call, the map will plot a point for the symbol each time the map is clicked and dispatch the drawComplete event on double click which will invoke the provided callback function.  Some MIL-STD-2525 symbols have a maximum number of points and drawing will automatically stop when this number is reached and dispacth the draw complete event.
        @function
        @param {function} drawCompleteCallback - Callback function that will be invoked after the symbol is drawn and the map is double clicked finishing the drawing of the symbol. The callback function should expect one parameter which is the drawComplete event with the coordinates of the drawn symbol. 
        @param {string} name - Display name for the multipoint MIL-STD-2525 symbol
        @param {string} id - Id of the multipoint MIL-STD-2525 symbol
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay containing the multipoint MIL-STD-2525 symbol
		@param {string} symbolCode - 15 character SIDC code for the multipoint MIL-STD-2525 symbol
		@param {object} modifiers - modifier object for the multipoint MIL-STD-2525 symbol
		@param {boolean} autoPopulate - Creates a default symbol for complex graphics like ambush at the center ov the current map view so user has a starting point before 3 clicks
        */
        drawMilStdMultipoint: function (drawCompleteCallback, name, id, sourceId, overlayId, symbolCode, modifiers, autoPopulate) {

            var comString,
                message;

            comString = '"' + name + '",';
            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += '"' + symbolCode + '"';
            if (modifiers !== null && modifiers !== undefined) {
                modifiersObject = {};
                modifiersObject.modifiers = modifiers;
                modString = JSON.stringify(modifiersObject);
                comString += ',"' + escape(modString) + '"';
            } else {
                comString += ',null';
            }
            if (autoPopulate === true) {
                comString += ',"true"';
            } else {
                comString += ',"false"';
            }
            message = 'drawMil2525Symbol(' + comString + ')';

            publishMessage(message);
            //map3DdrawEventHash.setItem(id, drawCompleteCallback);
            this.registerDrawingListener("drawComplete", drawCompleteCallback, id);
        },

        /**
        Add a 3D Shape to an overlay for display on the map.  
        @function 
        @param {string} name - Display name for the 3D shape
        @param {string} id - Id of the 3D shape
        @param {string} sourceId - Id of the data provider.  This should be a constant value used for all data from a single source
        @param {string} overlayId - Id of the overlay to which the 3D shape will be added
        @param {string} shapeType - Type of 3D shape to be drawn.  Choices are defined as constants in coreMapAPI such as CoreMapAPI.SHAPE3D_CAKE
        @see CoreMapAPI.SHAPE3D_CAKE
        @see CoreMapAPI.SHAPE3D_ROUTE
        @see CoreMapAPI.SHAPE3D_CYLINDER
        @see CoreMapAPI.SHAPE3D_ORBIT
        @see CoreMapAPI.SHAPE3D_POLYGON
        @see CoreMapAPI.SHAPE3D_RADARC
        @see CoreMapAPI.SHAPE3D_POLYARC
        @see CoreMapAPI.SHAPE3D_TRACK
        @param {string} description - HTML formatted string to be displayed in the info popup for the 3D shape
        @param {string} altitudeMode - Method used to define how altitude should be measured.  Choices are defined as constants in CoreMapAPI such as CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        @param {string} coordinates - Collection of coordinates for a 3D Symbol in OGC geometry string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} color - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. BB3366FF.
        @param {array} attributes - Array of 3D shape attribute objects.  Please see the 3D Map API developer guide for explanation of how to properly create this object
        @returns id of the 3D shape
        */
        add3DShape: function (name, id, sourceId, overlayId, shapeType, description, altitudeMode, coordinates, color, attributes) {
            var arttibutesObject = {},
                attString,
                comString,
                message;

            arttibutesObject.attributes = attributes;
            attString = JSON.stringify(arttibutesObject);
            attString = escape(attString);
            comString = '"' + name + '",';
            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += '"' + shapeType + '",';

            comString += '"' + escape(description) + '",';
            comString += '"' + altitudeMode + '",';
            comString += '"' + coordinates + '",';
            comString += '"' + color + '",';
            comString += '"' + attString + '"';

            message = 'add3DShape(' + comString + ')';

            publishMessage(message);
            return id;
        },

        /**
        Removes a graphic of any type - Point, Line, Polygon, 3D Shape, and MIL-STD-2525 Graphic  
        @function
        @param {string} id - Id of the graphic to remove
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay containing the graphic to remove
        */
        removeGraphic: function (id, sourceId, overlayId) {

            var comString = '"' + id + '",',
                message;

            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '"';


            message = 'removeGraphic(' + comString + ')';
            publishMessage(message);

        },

        /**
        Puts an existing map feature (point, line, polygon, MIL-STD-2525) into edit mode and centers the map on the feature to be edited.  Graphic update event will be fired when the feature is deselected from edit mode.
        @function
        @param {function} editCompleteCallback - Callback function which is invoked when the graphics is taken out of editing mode.  The callback function should expect one parameter which is the object returned with the graphic update event
        @param {string} id - Id of the graphic
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay containing the graphic
        */
        editGraphic: function (editCompleteCallback, id, sourceId, overlayId) {

            var comString = '"' + id + '",',
                message;

            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '"';


            message = 'editFeature(' + comString + ')';
            // map3DdrawEventHash.setItem(id, editCompleteCallback);
            this.registerDataListener(this.GRAPHIC_UPDATE, editCompleteCallback, id);
            publishMessage(message);

        },
        /**
        Removes an array of mixed graphic types - Point, Line, Polygon, 3D shape, and MIL-STD-2525 graphic  
        @function
        @param {array} graphicInfos - Array of simple objects with three properties: id, sourceId, and overlayId for each graphic that should be removed.  i.e. graphicsInfos = [(id:12345,sourceId:4t56ew,overlayId:4hgjks8sjr85j},{id:34567,sourceId:4t56ew,overlayId:4hgjks8sjr85j},{id:23456,sourceId:4t56ew,overlayId:4hgjks8sjr85j)]
        */
        removeGraphicBatch: function (graphicInfos) {
            var graphicsObject = {},
                graphicsString,
                message;

            graphicsObject.graphics = graphicInfos;
            graphicsString = JSON.stringify(graphicsObject);

            message = 'removeGraphicBatch("' + escape(graphicsString) + '")';
            publishMessage(message);

        },

        /**
        Add a polygon to an overlay for display on the map.  
        @function 
        @param {string} name - Display name for the polygon
        @param {string} id - Id of the polygon
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay to which the polygon will be added
        @param {string} coordinates - Collection of coordinates for a polygon in string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} description - HTML formatted string to be displayed in the info popup for the polygon
        @param {string} fillColor - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. 003366FF.
        @param {string} lineColor - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. 003366FF.
        @param {float}   lineThickness - float representing thickness of the line in pixels
        @param {string} altitudeMode - Value to determine how to calculate the alitude.  Options are defined as constants CoreMapAPI.ALTITUDE_ABSOLUTE, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND, CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND  
        @param {boolean} extrude - false by default.  If set to true the line will extend all the way to ground
        @param {object} options - Optional - NEW in 13.0.4 - The options object allows for customizations to the polygon styling and editing permissions 
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        @returns id of new polygon
        */
        addPolygon: function (name, id, sourceId, overlayId, coordinates, description, fillColor, lineColor, lineThickness, altitudeMode, extrude, modifiers) {
            var comString = '"' + name + '",',
                message,
                modifiersObject,
                modString;

            comString += '"' + id + '",';
            comString += '"' + sourceId + '",';
            comString += '"' + overlayId + '",';
            comString += '"' + coordinates + '",';
            comString += '"' + escape(description) + '",';
            comString += '"' + fillColor + '",';
            comString += '"' + lineColor + '",';
            comString += lineThickness + ',';
            comString += '"' + altitudeMode + '",';
            comString += extrude;
            if (modifiers !== null && modifiers !== undefined) {
                modifiersObject = {};
                modifiersObject.modifiers = modifiers;
                modString = JSON.stringify(modifiersObject);
                modString = escape(modString);
                comString += ',"' + modString + '"';
            }

            message = 'addPolygon(' + comString + ')';

            publishMessage(message);
            return id;
        },

        /**
        Updates an existing polygon on an overlay for display on the map.  
        @function
        @param {string} name - Display name for the polygon
        @param {string} id - Id of the polygon
        @param {string} sourceId - Id of the data provider
        @param {string} overlayId - Id of the overlay to which the polygon will be added
        @param {string} coordinates - Collection of coordinates for a polygon in string format. i.e. "longitude,latitude,altitude longitude,latitude,altitude longitude,latitude,altitude"  
        @param {string} description - HTML formatted string to be displayed in the info popup for the polygon
        @param {string} fillColor - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. 003366FF.
        @param {string} lineColor - Color in hex ARGB (Alpha, Red, Green, Blue) color i.e. 003366FF.
        @param {float}   lineThickness - float representing thickness of the line in pixels
        @param {string} altitudeMode - Value to determine how to calculate the alitude.  Options are defined as constants CoreMapAPI.ALTITUDE_ABSOLUTE, CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND, CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND  
        @param {boolean} extrude - false by default.  If set to true the line will extend all the way to ground
        @see CoreMapAPI.ALTITUDE_CLAMP_TO_GROUND
        @see CoreMapAPI.ALTITUDE_RELATIVE_TO_GROUND
        @see CoreMapAPI.ALTITUDE_ABSOLUTE
        */
        updatePolygon: function (name, id, sourceId, overlayId, coordinates, description, fillColor, lineColor, lineThickness, altitudeMode, extrude) {
            this.addPolygon(name, id, sourceId, overlayId, coordinates, description, fillColor, lineColor, lineThickness, altitudeMode, extrude);
        },

        /**
        Generates a unique GUID-like string (not truly a GUID) which can be used for graphic and overlay ids.  
        @function 
        @returns GUID-like string
        */
        createGUID: function () {
            var S4 = function () {
                return (((1 + Math.random()) * 0x10000) || 0).toString(16).substring(1);
            };
            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
        },

        /**
        Adds a callback function for the specified event type. 
        @function
        @param {string} type - Map event type to which the callback function will be registered as a listener. Map event type constants are properties of the CoreMapAPI instance and are listed below.
        @param {function} callback - Function to be called when the subscribed event is raised
        @see CoreMapAPI.MAP_MOVE
        @see CoreMapAPI.MAP_CLICK
        @see CoreMapAPI.MAP_DOUBLE_CLICK
        @see CoreMapAPI.MAP_READY
        */
        registerMapListener: function (type, callback) {
            if (map3DmapEventHash.getItem(type) !== null && map3DmapEventHash.getItem(type) !== undefined) {
                map3DmapEventHash.getItem(type).push(callback);
            } else {
                var callbacks = [];
                callbacks.push(callback);
                map3DmapEventHash.setItem(type, callbacks);
            }
        },

        /**
        Removes a callback function for the specified event type. 
        @function
        @param {string} type - Map event type from which the callback function will be removed as a listener. Map event type constants are properties of the CoreMapAPI instance and are listed below.
        @param {function} callback - Function to be removed as a listener
        @see CoreMapAPI.MAP_MOVE
        @see CoreMapAPI.MAP_CLICK
        @see CoreMapAPI.MAP_DOUBLE_CLICK
        @see CoreMapAPI.MAP_READY
        */
        removeMapListener: function (type, callback) {
            var callbackArray,
                len,
                i;

            if (map3DmapEventHash.getItem(type) !== null && map3DmapEventHash.getItem(type) !== undefined) {
                callbackArray = map3DmapEventHash.getItem(type);
                len = callbackArray.length;

                for (i = 0; i < len; i += 1) {
                    if (callbackArray[i] === callback) {
                        callbackArray.splice(i, 1);
                        return true;
                    }
                }
            }
            return false;
        },

        /**
        Adds a callback function for the specified event type. 
        @function
        @param {string} type - Data event type to which the callback function will be registered as a listener. Data event type constants are properties of the CoreMapAPI instance and are listed below.
        @param {function} callback - Function to be called when the subscribed event is raised
        @param {string} id - Optional parameter to filter events so the callback only fires for a specific graphic with the provided id
        @see CoreMapAPI.GRAPHIC_CLICK
        @see CoreMapAPI.GRAPHIC_DOUBLE_CLICK
        @see CoreMapAPI.GRAPHIC_UPDATE
        */
        registerDataListener: function (type, callback, id) {
            if (map3DdataEventHash.getItem(type) !== null && map3DmapEventHash.getItem(type) !== undefined) {
                map3DdataEventHash.getItem(type).push({
                    callback: callback,
                    id: id
                });
            } else {
                var callbacks = [];
                callbacks.push({
                    callback: callback,
                    id: id
                });
                map3DdataEventHash.setItem(type, callbacks);
            }
        },

        /**
        Removes a callback function for the specified event type. 
        @function
        @param {string} type - Data event type from which the callback function will be removed as a listener. Data event type constants are properties of the CoreMapAPI instance and are listed below.
        @param {function} callback - Function to be removed as a listener
        @see CoreMapAPI.GRAPHIC_CLICK
        @see CoreMapAPI.GRAPHIC_DOUBLE_CLICK
        @see CoreMapAPI.GRAPHIC_UPDATE
        */
        removeDataListener: function (type, callback, id) {

            callbacks = map3DdataEventHash.getItem(type),
            len,
            i,
            callbackFunction;

            if (callbacks !== null && callbacks !== undefined) {
                len = callbacks.length;
                for (i = 0; i < len; i += 1) {
                    callbackFunction = callbacks[i];
                    if (callbackFunction !== undefined && callbackFunction !== null) {
                        if (callbackFunction.callback === callback) {
                            if (id !== undefined && id !== null) {
                                if (callbackFunction.id !== undefined && callbackFunction.id !== null && callbackFunction.id !== "undefined" && callbackFunction.id !== "null") {
                                    if (id === callbackFunction.id) {
                                        callbacks.splice(i, 1);
                                    }
                                }
                            } else {
                                callbacks.splice(i, 1);
                            }
                        }
                    }
                }
            }
        },


        /**
        Adds a callback function for the specified event type. 
        @function
        @param {string} type - Drawing event type to which the callback function will be registered as a listener.
        @param {function} callback - Function to be called when the subscribed event is raised
        */
        registerDrawingListener: function (type, callback, id) {
            if (map3DdrawEventHash.getItem(type) !== null && map3DmapEventHash.getItem(type) !== undefined) {
                map3DdrawEventHash.getItem(type).push({
                    callback: callback,
                    id: id
                });
            } else {
                var callbacks = [];
                callbacks.push({
                    callback: callback,
                    id: id
                });
                map3DdrawEventHash.setItem(type, callbacks);
            }
        },

        /**
        Removes a callback function for the specified event type. 
        @function
        @param {string} type - Drawing event type from which the callback function will be removed as a listener.
        @param {function} callback - Function to be removed as a listener
        */
        removeDrawingListener: function (type, callback) {
            callbacks = map3DdrawEventHash.getItem(type),
            len,
            i,
            callbackFunction;

            if (callbacks !== null && callbacks !== undefined) {
                len = callbacks.length;
                for (i = 0; i < len; i += 1) {
                    callbackFunction = callbacks[i];
                    if (callbackFunction !== undefined && callbackFunction !== null) {
                        if (callbackFunction.callback === callback) {
                            if (id !== undefined && id !== null) {
                                if (callbackFunction.id !== undefined && callbackFunction.id !== null && callbackFunction.id !== "undefined" && callbackFunction.id !== "null") {
                                    if (id === callbackFunction.id) {
                                        callbacks.splice(i, 1);
                                    }
                                }
                            } else {
                                callbacks.splice(i, 1);
                            }
                        }
                    }
                }
            }
        },

        /**
        Drapes an image over the base map layer with the four corners of the images placed at the given coordinates  
        @function
        @param {string} url - URL to the image.  Must be a fully qualified URL as the Google Earth plugin can not use relative paths.
        @param {float}   left - Coordinate for the left edge of the image
        @param {float}   bottom - Coordinate for the bottom edge of the image
        @param {float}   right - Coordinate for the right edge of the image
        @param {float}   top - Coordinate for the top edge of the image
        */
        addImageOverlay: function (url, left, bottom, right, top) {
            var comString = '"' + url + '",',
                message;

            comString += left + ',';
            comString += bottom + ',';
            comString += right + ',';
            comString += top;


            message = 'addImageOverlay(' + comString + ')';

            publishMessage(message);
        },

        /**
        Removes an image overlay added via addImageOverlay
        @function
        @param {string} url - URL used to load the image when it was added via addImageOverlay.
        @see CoreMapAPI.addImageOverlay
        */
        removeImageOverlay: function (url) {
            var message = 'removeImageOverlay("' + url + '")';
            publishMessage(message);
        },

        /**
        Sets the view of the map to a given map scale
        @function
        @param int scale - number representing the scale. If the desired scale is 1:2,000,000 then scale would be set to 2000000.
        */
        setScale: function (scale) {
            var message = 'setScale(' + scale + ')';
            publishMessage(message);
        },

        /**
        Sets the view of the map to a given map scale
        @function
        @param {View} view - obecjt containing the view properties to set.  .
        */
        setView: function (view) {
            var message;
            view = JSON.stringify(view);
            message = 'setView(' + view + ')';
            publishMessage(message);
        },

        draw3dShape: function (drawCompleteCallback, altitude, coords, shapeOpts) {
            var shapeOptsObject,
                shapeOptsString,
                comString,
                message;


            if (typeof (shapeOpts) !== 'undefined') {

                //set default id if none specified
                shapeOpts = shapeOpts || {};
                shapeOpts.id = shapeOpts.id || "draw-3d-default-id";

                shapeOptsObject = {};
                shapeOptsObject.shapeOpts = shapeOpts;
                shapeOptsString = JSON.stringify(shapeOptsObject);
                shapeOptsString = shapeOptsString.replace(/"/g, "_replaceme_");

                comString = '"' + altitude + '",';
                comString += '"' + coords + '",';
                comString += '"' + shapeOptsString + '"';

                message = 'draw3dShape(' + comString + ')';

                map3DdrawEventHash.setItem(shapeOpts.id, drawCompleteCallback);
                publishMessage(message);
            }
        },

        edit3dShape: function (drawCompleteCallback, altitude, coords, shapeOpts) {
            var shapeOptsObject,
                shapeOptsString,
                comString,
                message;

            if (typeof (shapeOpts) === 'undefined') {

                //set default id if none specified
                shapeOpts = shapeOpts || {};
                shapeOpts.id = shapeOpts.id || "edit-3d-default-id";

                shapeOptsObject = {};
                shapeOptsObject.shapeOpts = shapeOpts;
                shapeOptsString = JSON.stringify(shapeOptsObject);
                shapeOptsString = shapeOptsString.replace(/"/g, "_replaceme_");

                comString = '"' + altitude + '",';
                comString += '"' + coords + '",';
                comString += '"' + shapeOptsString + '"';

                message = 'edit3dShape(' + comString + ')';
                map3DdrawEventHash.setItem(shapeOpts.id, drawCompleteCallback);
                publishMessage(message);
            }
        },

        goToLocationById: function (id) {

            //set default id if none specified			
            comString = '"' + id + '"';

            message = 'goToLocationById(' + comString + ')';
            publishMessage(message);

        }
    };
}());


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

var JSON;
if (!JSON) {
    JSON = {};
}

(function () {
    "use strict";

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf()) ?
                this.getUTCFullYear() + '-' +
                f(this.getUTCMonth() + 1) + '-' +
                f(this.getUTCDate()) + 'T' +
                f(this.getUTCHours()) + ':' +
                f(this.getUTCMinutes()) + ':' +
                f(this.getUTCSeconds()) + 'Z' : null;
        };

        String.prototype.toJSON =
            Number.prototype.toJSON =
            Boolean.prototype.toJSON = function (key) {
                return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = { // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"': '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

        // If the string contains no control characters, no quote characters, and no
        // backslash characters, then we can safely slap some quotes around it.
        // Otherwise we must also replace the offending characters with safe escape
        // sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string' ? c :
                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }


    function str(key, holder) {

        // Produce a string from holder[key].

        var i, // The loop counter.
            k, // The member key.
            v, // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

        // If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
            typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

        // If we were called with a replacer function, then call the replacer to
        // obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

        // What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

            // JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

            // If the value is a boolean or null, convert it to a string. Note:
            // typeof null does not produce 'null'. The case is included here in
            // the remote chance that this gets fixed someday.

            return String(value);

            // If the type is 'object', we might be dealing with an object or an array or
            // null.

        case 'object':

            // Due to a specification blunder in ECMAScript, typeof null is 'object',
            // so watch out for that case.

            if (!value) {
                return 'null';
            }

            // Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

            // Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

                // The value is an array. Stringify every element. Use null as a placeholder
                // for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

                // Join all of the elements together, separated with commas, and wrap them in
                // brackets.

                v = partial.length === 0 ? '[]' : gap ?
                    '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
                    '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

            // If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === 'string') {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

                // Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

            // Join all of the member texts together, separated with commas,
            // and wrap them in braces.

            v = partial.length === 0 ? '{}' : gap ?
                '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
                '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

    // If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

            // The stringify method takes a value and an optional replacer, and an optional
            // space parameter, and returns a JSON text. The replacer can be a function
            // that can replace values, or an array of strings that will select the keys.
            // A default replacer method can be provided. Use of the space parameter can
            // produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

            // If the space parameter is a number, make an indent string containing that
            // many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

                // If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

            // If there is a replacer, it must be a function or an array.
            // Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                (typeof replacer !== 'object' ||
                    typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

            // Make a fake root object containing our value under the key of ''.
            // Return the result of stringifying the value.

            return str('', {
                '': value
            });
        };
    }


    // If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

            // The parse method takes a text and an optional reviver function, and returns
            // a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

                // The walk method is used to recursively walk the resulting structure so
                // that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


            // Parsing happens in four stages. In the first stage, we replace certain
            // Unicode characters with escape sequences. JavaScript handles many characters
            // incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

            // In the second stage, we run the text against regular expressions that look
            // for non-JSON patterns. We are especially concerned with '()' and 'new'
            // because they can cause invocation, and '=' because it can cause mutation.
            // But just to be safe, we want to reject all unexpected forms.

            // We split the second stage into 4 regexp operations in order to work around
            // crippling inefficiencies in IE's and Safari's regexp engines. First we
            // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
            // replace all simple value tokens with ']' characters. Third, we delete all
            // open brackets that follow a colon or comma or that begin the text. Finally,
            // we look to see that the remaining characters are only whitespace or ']' or
            // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/
                .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                    .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                    .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

                // In the third stage we use the eval function to compile the text into a
                // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
                // in JavaScript: it can begin a block or an object literal. We wrap the text
                // in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

                // In the optional fourth stage, we recursively walk the new structure, passing
                // each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function' ?
                    walk({
                        '': j
                    }, '') : j;
            }

            // If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());